package cz.muni.fi.pa165.sme.web.pages.burnedCalories;

import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import cz.muni.fi.pa165.sme.api.BurnedCaloriesService;
import cz.muni.fi.pa165.sme.api.to.BurnedCaloriesTO;
import cz.muni.fi.pa165.sme.web.common.TrackerDataTable;
import cz.muni.fi.pa165.sme.web.converters.ConvertUtils;
import cz.muni.fi.pa165.sme.web.fo.BurnedCaloriesFO;
import cz.muni.fi.pa165.sme.web.pages.TemplatePage;
import cz.muni.fi.pa165.sme.web.panels.DeletePanel;
import cz.muni.fi.pa165.sme.web.panels.EditPanel;
import cz.muni.fi.pa165.sme.web.security.Authorizer;
import org.apache.wicket.authorization.Action;
import org.apache.wicket.authroles.authorization.strategies.role.Roles;
import org.apache.wicket.authroles.authorization.strategies.role.annotations.AuthorizeAction;
import org.apache.wicket.extensions.markup.html.repeater.data.grid.ICellPopulator;
import org.apache.wicket.extensions.markup.html.repeater.data.sort.SortOrder;
import org.apache.wicket.extensions.markup.html.repeater.data.table.AbstractColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.IColumn;
import org.apache.wicket.extensions.markup.html.repeater.data.table.PropertyColumn;
import org.apache.wicket.extensions.markup.html.repeater.util.SortableDataProvider;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.repeater.Item;
import org.apache.wicket.model.CompoundPropertyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.model.ResourceModel;
import org.apache.wicket.spring.injection.annot.SpringBean;
import org.springframework.core.convert.ConversionService;

/**
 * @author jirankova
 */
@AuthorizeAction(action = Action.RENDER, roles = { Roles.ADMIN, Roles.USER})
public class CaloriesListPage extends TemplatePage {

	private final NumberFormat numberFormat;

	@SpringBean
	private BurnedCaloriesService service;

	@SpringBean(name = "conversionServiceFe")
	private ConversionService conversionService;

	public CaloriesListPage() {
		//page title
		add(new Label("title", new ResourceModel("calories.add.title")));

		//table containing calories
		final WebMarkupContainer table = new TrackerDataTable<BurnedCaloriesFO>("caloriesTable", getColumns(), new CaloriesDataProvider(
				ConvertUtils.convertList(service.findAllBurnedCalories(), conversionService, BurnedCaloriesFO.class)));
		table.setOutputMarkupId(true);
		add(table);

		numberFormat = NumberFormat.getNumberInstance(getLocale());
	}

	/**
	 * Provide columns to the calories table
	 * @return list of calories' columns
	 */
	private List<IColumn<BurnedCaloriesFO>> getColumns() {
		final List<IColumn<BurnedCaloriesFO>> columns = new ArrayList<IColumn<BurnedCaloriesFO>>();

		//column for sport activity name
		columns.add(new PropertyColumn<BurnedCaloriesFO>(new ResourceModel("activityName"), "activityName") {
			@Override
			public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> item, final String componentId,
					final IModel<BurnedCaloriesFO> rowModel) {
				item.add(new Label(componentId, rowModel.getObject().getSportActivity().getTitle()));
			}
		});

		//for the weight...
		columns.add(new PropertyColumn<BurnedCaloriesFO>(new ResourceModel("calories.weight"), "weight") {
			@Override
			public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> item, final String componentId,
					final IModel<BurnedCaloriesFO> rowModel) {
				item.add(new Label(componentId, numberFormat.format(rowModel.getObject().getWeight())));
			}
		});

		//...and speed...
		columns.add(new PropertyColumn<BurnedCaloriesFO>(new ResourceModel("calories.speed"), "speed") {
			@Override
			public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> item, final String componentId,
					final IModel<BurnedCaloriesFO> rowModel) {
				item.add(new Label(componentId, numberFormat.format(rowModel.getObject().getSpeed())));
			}
		});

		//...these calories are burned
		columns.add(new PropertyColumn<BurnedCaloriesFO>(new ResourceModel("calories.calories"), "calories") {
			@Override
			public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> item, final String componentId,
					final IModel<BurnedCaloriesFO> rowModel) {
				item.add(new Label(componentId, numberFormat.format(rowModel.getObject().getCalories())));
			}
		});

		if(Authorizer.isAdminLogged()) {
			//column to edit entry
			columns.add(new EditColumn(new ResourceModel("edit")));

			//column to delete entry
			columns.add(new RemoveColumn(new ResourceModel("remove")));
		}

		return columns;
	}

	/**
	 * Class to create a column to edit entry
	 */
	private class EditColumn extends AbstractColumn<BurnedCaloriesFO> {
		public EditColumn(final IModel<String> model) {
			super(model);
		}

		@Override
		public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> cellItem, final String componentId,
				final IModel<BurnedCaloriesFO> rowModel) {
			cellItem.add(new EditPanel(componentId, rowModel) {
				@Override
				public void onEdit() {
					setResponsePage(new CaloriesEditPage(rowModel.getObject()));
				}
			});
		}
	}

	/**
	 * Class to create a column to remove calories entry.
	 */
	private class RemoveColumn extends AbstractColumn<BurnedCaloriesFO> {
		public RemoveColumn(final IModel<String> model) {
			super(model);
		}

		@Override
		public void populateItem(final Item<ICellPopulator<BurnedCaloriesFO>> cellItem, final String componentId,
				final IModel<BurnedCaloriesFO> rowModel) {
			cellItem.add(new DeletePanel(componentId, rowModel) {
				@Override
				public void onDelete() {
					final BurnedCaloriesFO burnedCaloriesFO = rowModel.getObject();
					service.deleteBurnedCalories(conversionService.convert(burnedCaloriesFO, BurnedCaloriesTO.class));
					setResponsePage(CaloriesListPage.class);
				}
			});
		}
	}

	/**
	 * Class to provide data for the burned calories table.
	 */
	private class CaloriesDataProvider extends SortableDataProvider<BurnedCaloriesFO> {
		private final List<BurnedCaloriesFO> burnedCaloriesFOList;

		/**
		 * Constructor.
		 * @param caloriesFOs list of burned calories to fill in the table
		 */
		public CaloriesDataProvider(final List<BurnedCaloriesFO> caloriesFOs) {
			burnedCaloriesFOList = caloriesFOs;
			setSort("calories", SortOrder.ASCENDING);
		}

		@Override
		public Iterator<? extends BurnedCaloriesFO> iterator(final int first, final int count) {
			return burnedCaloriesFOList.subList(first, first+count).iterator();
		}

		@Override
		public int size() {
			return burnedCaloriesFOList.size();
		}

		@Override
		public IModel<BurnedCaloriesFO> model(final BurnedCaloriesFO object) {
			return new CompoundPropertyModel<BurnedCaloriesFO>(new LoadableDetachableModel<BurnedCaloriesFO>() {
				@Override
				protected BurnedCaloriesFO load() {
					return object;
				}
			});
		}
	}
}
